//
//  CCSClient.m
//  ivcs_ios_demo
//
//  Created by zealcomm user on 2020/10/22.
//  Copyright © 2020 zealcomm user. All rights reserved.
//
#import <IRTCSDK.h>
#import "CCSClient.h"
#import "Tool.h"
#import "ZealcommNetWorkTool.h"
#import "IvcsBaseDelegate.h"
#import "NSObject+Helper.h"
#import "Constant.h"

static NSString *ivcsCcsErrorDomain = @"zealcomm.ivcs.ccs";

@interface CCSClient()<NSURLSessionDelegate , CCSClientDelegate>

/// socketManager
@property(strong,nonatomic)SocketManager* manager;

/// socketIo ticket
@property(nonatomic,copy)NSString *ticket;

/// socketIo refresh timer
@property(nonatomic,strong)NSTimer *socketTimer;

/// socketIo is connected default = false;
@property(assign,nonatomic)BOOL connected;

@property (nonatomic,strong)NSString *from;

@property (nonatomic,strong)NSString *to;
@end

@implementation CCSClient

relizeSingleInstance()

-(void)connectWithUrl:(NSString *)ccsUrl andToken:(NSString *)token complete:(completeBlock)complete{
    self.baseUrl = ccsUrl ;
    NSString *connectUrl = [NSString stringWithFormat:@"%@/socket.io/?token=%@&servicePath=_ivcs_ccs",ccsUrl,token];
    NSURL *url = [[NSURL alloc] initWithString:connectUrl];
    
    NSDictionary *header = @{
        @"token":token,
        @"servicePath":@"_ivcs_ccs"
    };
    // TODO 后续我们要支持reconnect，你要看下怎么实现的。@reconnect=YES。。目前默认重连次数是10次。允许重连10次。所以后面需要监听Reconnect/reconnect-error等相关事件
    NSDictionary *config = @{
                             @"log": @YES,
                             // @"forcePolling": @NO,
                             //@"compress": @YES
                             @"forceWebsockets":@YES,
                             @"reconnect":@NO,
                             @"secure":@NO,
                             @"force new connection":@YES,
                             //@"query":query,
                             @"connectParams":header,
                             @"sessionDelegate":self,
                             // @"selfSigned":@YES,
                             // @"extraHeaders":header
                             };
    NSLog(@"connect url,%@,,para,,%@",connectUrl,config);
    self.manager = [[SocketManager alloc] initWithSocketURL:url config:config];
    self.socket = self.manager.defaultSocket;
    
    CallBackObject *callBackResult =[[CallBackObject alloc] init];
    
    NSUUID *uuid = [self.socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
        MyLog(@"%@,%@,socketio connected,data:%@",self.socket,[Tool getCurrentTimes],data);
        callBackResult.code = 200;
        self.accessToken = token;
        self.delegate = self;
        self.connected = true;
        [self listenSessionMessage];
        complete(callBackResult);
    }];
    NSLog(@"ccs connect uuid:%@" , uuid);
    
    [self.socket on:@"error" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ack) {
        NSLog(@"%@,%@,socketio error,data:%@",self.socket,[Tool getCurrentTimes],data);
        callBackResult.code = 301;
        callBackResult.message = @"error";
        complete(callBackResult);
        [self.socket disconnect];
    }];
    
    [self.socket on:@"connect_timeout" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ack) {
        NSLog(@"%@,%@,socketio connect_timeout,data:%@",self.socket,[Tool getCurrentTimes],data);
        callBackResult.code = 301;
        callBackResult.message = @"connect_timeout";
        complete(callBackResult);
        [self.socket disconnect];
    }];

    [self.socket on:@"disconnect" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ack) {
        NSLog(@"%@,%@,socketio disconnect,data:%@",self.socket,[Tool getCurrentTimes],data);
        self.connected = false;
      }];
    [self.socket connect];
}

-(void)resumeCcsConnect{
    if (nil == self.ticket) {
        return;
    }
    [[self.socket emitWithAck:@"resume-connection" with:@[self.ticket]] timingOutAfter:0 callback:^(NSArray * _Nonnull result) {
         NSLog(@"%@,%@,socketio resume-connection,data:%@",self.socket,[Tool getCurrentTimes],result);
        if ([result.firstObject isEqualToString:@"ok"]) {
            NSDictionary *info = result.lastObject;
            self.ticket = [info valueForKey:@"ticket"];
        }else{
            if (self.delegate && [self.delegate respondsToSelector:@selector(ccsErrorWithCode:andMessage:)]) {
                [self.delegate ccsErrorWithCode:resumeCCSSocketIOFailed andMessage:@"resume-connection error"];
            }
        }
    }];
}

-(void)requestSession:(NSDictionary *)requestParameter onSuccess:(void (^)(NSDictionary * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[self.socket emitWithAck:@"request-session" with:@[requestParameter]] timingOutAfter:0 callback:^(NSArray* data) {
        NSLog(@"%@,%@,socketio request-session,data:%@",self.socket,[Tool getCurrentTimes],data);
        if([data.firstObject isEqualToString:@"ok"]){
            NSDictionary *info = data.lastObject;
            self.roomtoken = [info valueForKey:@"roomToken"];
            self.clientId = [info valueForKey:@"clientId"];
            self.ticket = [info valueForKey:@"ticket"];
            NSInteger ccsTicketRefreshTime = [[info valueForKey:@"refersh_ticket_time"] integerValue]/1000;
            if (!self.socketTimer) {
               self.socketTimer = [NSTimer scheduledTimerWithTimeInterval:ccsTicketRefreshTime target:self selector:@selector(refreshTicket) userInfo:nil repeats:YES];
            }
            self.userList  = [NSMutableArray array];
            onSuccess(info);
        }else{
           NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:5008 userInfo:data.lastObject];
           onFailure(error);
        }
    }];
}

- (void)joinSession:(NSString *)invitationId withSessionId:(NSString *)sessionId onSuccess:(void (^)(NSDictionary * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[self.socket emitWithAck:@"join-session" with:@[@{
        @"media": @"video",
        @"userData": @{
            @"skill": @"",
            @"specifyAgent": @""
        },
        @"sessionId": sessionId,
        @"clientInfo": @{
            @"type": @"ios"
        },
        @"invitationId": invitationId
      }]] timingOutAfter:0 callback:^(NSArray * _Nonnull result) {
        if ([@"ok" isEqualToString:result[0]]) {
            onSuccess(result[1]);
        }else{
            NSError *error = [[NSError alloc] init];
            onFailure(error);
        }
    }];
}

/// @param parameter @{@"reason":@""}
-(void)quitSession:(id)parameter onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[self.socket emitWithAck:@"quit-session" with:@[@{}]] timingOutAfter:0 callback:^(NSArray * _Nonnull result) {
       NSLog(@"%@,%@,socketio quit-session,data:%@",self.socket,[Tool getCurrentTimes],result);
       [self.socketTimer invalidate];
       self.socketTimer = nil;
       [self.manager disconnectSocket:self.socket];
       //[self.socket disconnect];
       if ([result.firstObject isEqualToString:@"ok"]) {
           NSLog(@"CCSClient: ccs quit session success.");
           onSuccess();
       }else{
           NSLog(@"CCSClient: ccs quit session failure.");
           NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:5009 userInfo:result.lastObject];
           onFailure(error);
       }
   }];
}


+(void)validateCcsClient:(CCSClient *)client onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    if (!client) {
        NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:5001 userInfo:@{@"message":@"ccs client is null"}];
        onFailure(error);
        return;
    }else if (!client.accessToken){
        NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:5002 userInfo:@{@"message":@"ccs client accesstoken is null"}];
        onFailure(error);
        return;
    }else if (!client.connected){
        NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:5003 userInfo:@{@"message":@"ccs client accesstoken is disconnected"}];
        onFailure(error);
        return;
    }
    onSuccess();
}

/// 只能在 request-session 后调用，否则会导致连接中断
-(void)refreshTicket{
    [[self.socket emitWithAck:@"refresh-ticket" with:@[]] timingOutAfter:0 callback:^(NSArray * _Nonnull data) {
        MyLog(@"%@,%@,socketio refresh-ticket,data:%@",self.socket,[Tool getCurrentTimes],data);
        if ([data.firstObject isEqualToString:@"ok"]) {
            NSDictionary *info = data.lastObject;
            // 里面还有 clientId 暂时没用到
            self.ticket = [info valueForKey:@"ticket"];
        }else{
            if (self.delegate && [self.delegate respondsToSelector:@selector(ccsErrorWithCode:andMessage:)]) {
                [self.delegate ccsErrorWithCode:refreshCCSSocketIOTicketFailed andMessage:@"refresh-ticket error"];
            }
        }
    }];
}

/**
 * 用于 ai 坐席
 * @param aiId 机器人坐席的 id
 */
- (void) customerJoinedRoomWithId:(NSString *) aiId{
    ZcoModelProfile *profile = [[ZcoModelProfile alloc] init];
    profile.fullName = self.userInfo.tokenData.data.profile.fullName;
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
    NSDictionary *data = @{
        @"at":[formatter stringFromDate: [NSDate date]],
        @"status":@"customer-join-room",
        @"participantId":self.irtcSDK.participantId,
        @"user":profile.toDictionary
    };
    [self sendMessageWithType:@"peer-status" from:self.clientId to:aiId data:data onSuccess:^{
        MyLog(@"发送 customer-join-room 成功！");
        } onFailure:^(NSError * _Nonnull error) {
            MyLog(@"发送 customer-join-room 失败:%@" , error);
        }];
}

-(void)listenSessionMessage{
     [self.socket on:@"session-message" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ack) {
         if (self.messageDelegate) {
             [self.messageDelegate onCcsServerMessage:data];
         }
         NSDictionary *message = data.firstObject;
         ZcoModelCcsMessage *ccsMessage = [[ZcoModelCcsMessage alloc] initWithDictionary:message] ;
         SessionMessageType type = ccsMessage.type;
         self.from = ccsMessage.from;
         self.to = ccsMessage.to;
         NSDictionary *dataInfo = ccsMessage.data;
         MyLog(@"receiveCcsMessage: %@" , [self toJsonString:message]);
         if ([type isEqualToString:@"invitation-progress"]) {
             if (self.delegate && [self.delegate respondsToSelector:@selector(onInvitationProgress:)]) {
                 [self.delegate onInvitationProgress:message];
             }
         }
         else if ([type isEqualToString:@"peer-status"]){
             //系统消息
             if([[dataInfo valueForKey:@"status"] isEqualToString:@"ready-to-talk"]){
                 [self readyToTalkToRoles:nil onSuccess:^{
                     
                 } onFailure:^(NSError * _Nonnull error){
                     
                 }];
                 //客服视频准备就绪
                 if (self.delegate && [self.delegate respondsToSelector:@selector(agentVideoReadyToTalk)]) {
                     [self.delegate agentVideoReadyToTalk];
                 }
             }
             else if([[dataInfo valueForKey:@"status"] isEqualToString:@"joined"]){
                 //其他用户加入
                 ZcoModelMember *joinedInfo = [[ZcoModelMember alloc] initWithDictionary:ccsMessage.data] ;
                 if (joinedInfo.user.profile.isRobot) {
                     self.irtcSDK.lastAiAgentVideoLabel = joinedInfo.getVideoLabel;
                     if (self.irtcSDK.participantId == NULL || self.irtcSDK.participantId.length == 0) {
                         [self.irtcSDK joinRoomWithToken:self.accessToken onSuccess:^(IRTCConferenceInfo * _Nonnull info) {
                             [self customerJoinedRoomWithId:joinedInfo.idField];
                         } onFailure:^(NSError * _Nonnull error) {
                             
                         }];
                     }else{
                         [self customerJoinedRoomWithId:joinedInfo.idField];
                     }
                 }
                 [self.userList addObject:ccsMessage.data];
                 if (self.delegate && [self.delegate respondsToSelector:@selector(onJoinSession:)]) {
                     [self.delegate onJoinSession:dataInfo];
                 }
             }else if([[dataInfo valueForKey:@"status"] isEqualToString:@"quit"]){
                 //其他用户退出
                 [self.userList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                     if ([[obj valueForKey:@"id"] isEqualToString:[dataInfo valueForKey:@"id"]]) {
                         *stop = YES;
                         if (*stop == YES) {
                             [self.userList removeObjectAtIndex:idx];
                         }
                     }
                     if (*stop) {
                         NSLog(@"now userList is %@",self.userList);
                     }
                 }];
                 if (self.delegate && [self.delegate respondsToSelector:@selector(onQuitSession:)]) {
                     [self.delegate onQuitSession:dataInfo];
                 }
             }else if([[dataInfo valueForKey:@"status"] isEqualToString:@"hold-on"]){
                 //当前坐席离开，转接其他坐席
                 if (self.delegate && [self.delegate respondsToSelector:@selector(onHoldOn)]) {
                     [self.delegate onHoldOn];
                 }
                 //TODO 发送message给坐席，告诉坐席消息已收到
             }
         }
     }];
            
}

-(void)onDrop{
    [self.socket on:@"drop" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ack) {
        NSLog(@"%@,%@,socketio drop,data:%@",self.socket,[Tool getCurrentTimes],data);
        if (self.delegate && [self.delegate respondsToSelector:@selector(onDrop:)]) {
            [self.delegate onDrop:@{
                @"code":@"401",
                @"message":data.lastObject,
            }];
        }
    }];
}

-(void)shareResourceWithType:(NSString *)type resourceUrl:(NSString *)url resourceName:(nonnull NSString *)name toRoles:(nonnull NSString *)roles onSuccess:(nonnull void (^)(void))onSuccess onFailure:(nonnull void (^)(NSError * _Nonnull))onFailure{
    NSDictionary *data = @{
        @"type":type,
        @"url":url,
        @"name":name
    };
    [self sendMessageWithType:@"link" from:self.clientId to:roles data:data onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
    
}

-(void)shareResourceWithType:(NSString *)type uploadUrl:(NSString *)uploadUrl fileData:(NSData *)fileData fileName:(NSString *)fileName mimeType:(NSString *)mimeType toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[ZealcommNetWorkTool sharedNetWorkTool] Upload:uploadUrl fileData:fileData fileName:fileName mimeType:mimeType parameters:nil HeaderKeyValues:nil success:^(id  _Nonnull responseObject) {
        NSString *url = [[responseObject valueForKey:@"data"] valueForKey:@"url"];
        [self shareResourceWithType:type resourceUrl:url resourceName:fileName toRoles:roles onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } failure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

/// 告知对方，本地音视频已准备完成
/// @param roles 发送给的角色 默认是'agents'
/// @param onSuccess 成功
/// @param onFailure 失败
-(void)readyToTalkToRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    if (roles == nil || roles == NULL || [roles isKindOfClass:[NSNull class]] ||[[roles stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) {
        roles = @"agents";
    }
    NSDictionary *data = @{
        @"status":@"ready-to-talk",
        @"participantId":self.irtcSDK.participantId,
        @"user":[self.userInfo.tokenData.data.profile toDictionary]
    };
    [self sendMessageWithType:@"peer-status" from:self.clientId to:roles data:data onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)sendCustomMessage:(NSString *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self sendMessageWithType:@"custom" from:self.from to:roles data:data onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
        onFailure(errorDic);
    }];
}

-(void)sendTextMessage:(NSString *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
//    以前是roles，考虑到三方，需要设置为@“others”
    [self sendMessageWithType:@"text" from:self.clientId to:@"others" data:data onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
        onFailure(errorDic);
        
    }];
}

-(void)sendMessageConfirmation:(ZcoModelConfirmData *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self sendMessageWithType:@"message-confirmation" from:self.clientId to:roles data:data onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
        onFailure(errorDic);
        
    }];
}

-(void)sendSnapshotMessage:(NSDictionary * _Nonnull)data toRoles:(NSString * __nullable)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self sendMessageWithType:@"link" from:self.clientId to:(roles == nil?@"agents":roles) data:data onSuccess:^{
            if(onSuccess){
                onSuccess();
            }
        } onFailure:^(NSError * _Nonnull error){
            if (onFailure) {
                NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
                onFailure(errorDic);
                
                
            }
        }];
}

-(void)sendFormData:(NSDictionary *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self sendMessageWithType:@"form" from:self.clientId to:roles data:data onSuccess:^{
        onSuccess();
    } onFailure:^(NSError * _Nonnull error) {
        NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
        onFailure(errorDic);
        
    }];
}

- (void)sendPeerCMD:(ZcoModelCMD *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull error))onFailure{
    [self sendMessageWithType:SessionMessageTypePeerCmd from:self.to to:self.from data:cmd onSuccess:onSuccess onFailure:onFailure];
    
}

-(void)sendNormalSession:(NSDictionary *)cmd with:(NSString *)type to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self sendMessageWithType:type from:self.to to:roles data:cmd onSuccess:onSuccess onFailure:onFailure];
}

-(void)sendCmdCancleMessage:(ZcoModelCMD *)data toRoles:(NSString * __nullable)roles onSuccess:(void (^ __nullable)(void))onSuccess onFailure:(void (^ __nullable)(NSError * _Nonnull error))onFailure{
    [self sendMessageWithType:SessionMessageTypePeerCancel from:self.to to:self.from data:data onSuccess:onSuccess onFailure:onFailure];
}

- (void)sendPeerResponse:(ZcoModelCMD *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull error))onFailure{
    [self sendMessageWithType:SessionMessageTypePeerResponse from:self.clientId to:roles data:cmd onSuccess:onSuccess onFailure:onFailure];
}

- (void)sendHandWritingMessage:(NSString *)msg to:(nonnull NSString *)roles{
    ZcoModelCMD *cmd = [[ZcoModelCMD alloc] init];
    cmd.cmd = PeerCmdTypeGetHandwriting;
    cmd.data = @{
        @"stroke":msg
    };
    cmd.status = CmdStatusInProgress;
    [self sendPeerResponse:cmd to:roles onSuccess:^{} onFailure:^(NSError * _Nonnull error) {}];
}


-(void)invite:(NSString *)invitationId withBizScreen:(NSString *)screen andCustomer:(NSDictionary *)customer  onSuccess:(void (^)(NSDictionary * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[self.socket emitWithAck:@"invite" with:@[
        customer
     ]] timingOutAfter:0 callback:^(NSArray * _Nonnull result) {
        NSLog(@"result[0]=====%@",result[1]);
        if ([@"ok" isEqualToString:result[0]]) {
            onSuccess(result[1]);
        }else{
            NSError *error = [[NSError alloc] init];
            onFailure(error);
        }
    }];
}
#pragma mark 邀请
-(void)inviteWithAgent:(NSString *)agent andBizSceneName:(NSString *)bizSceneName witCustomer:(NSDictionary *)type onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull error))onFailure{
    [self invite:agent withBizScreen:bizSceneName andCustomer:type  onSuccess:^(NSDictionary * _Nonnull success) {
// 三方
        if ([bizSceneName isEqualToString:@"invite-multiple"]) {
            [self onHoldOn];
            [self quitSession:@"" onSuccess:^{
                            
            } onFailure:^(NSError * _Nonnull error) {
                NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
                  onFailure(errorDic);
                
            }];
        }
        } onFailure:^(NSError * _Nonnull failure) {
            NSError *errorDic = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3006 userInfo:@{@"message":@"amsClient发送消息失败,ams服务异常,消息无法发送"}];
              onFailure(errorDic);
        }];
}
-(void)sendMessageWithType:(NSString *)type from:(NSString *)clientId to:(NSString *)roles data:(id )message onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull error))onFailure{
    id data ;
    if ([message respondsToSelector:@selector(toDictionary)]) {
        data = [message performSelector:@selector(toDictionary)];
    }else{
        data = message;
    }
    NSDictionary *msg = @{
                             @"type":type,
                             @"id":[NSNumber numberWithLong:arc4random() % 10000000000000],
                             @"from":clientId,
                             @"to":roles,
                             @"data":data
                             };
       MyLog(@"sendSessionMessage:%@",[self toJsonString:msg]);
       [[self.socket emitWithAck:@"session-message" with:@[msg]] timingOutAfter:0 callback:^(NSArray * _Nonnull data) {
           MyLog(@"sendSessionMessage result:%@",data.firstObject);
           if ([data.firstObject isEqualToString:@"ok"]) {
               if (onSuccess) {
                   onSuccess();
               }
           }else{
               if (onFailure) {
                   NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:5004 userInfo:@{@"message":data.lastObject}];
                   onFailure(error);
                   
               }
           }
       }];
}


-(void)dropMessageWith:(NSDictionary *)dic{
    
    [[self.socket emitWithAck:@"drop-client" with:@[dic]]timingOutAfter:0 callback:^(NSArray * _Nonnull response) {
            
    }];
}

-(void)screenShare:(NSDictionary *)dic{
    [[self.socket emitWithAck:@"unpublish" with:@[dic]]timingOutAfter:0 callback:^(NSArray * _Nonnull response) {
            
    }];
}

- (void)sendPeerState:(NSDictionary *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull error))onFailure{
    
    [self sendMessageWithType:SessionMessageTypePeerStatus from:self.to to:@"customers" data:cmd onSuccess:onSuccess onFailure:onFailure];
}

#pragma mark socketIo with selfCredential
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error{
    NSLog(@"URLSession,didBecomeInvalidWithError%@,,%@",session,error);
}

- (void)URLSession:(NSURLSession *)session
 didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
   completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSLog(@"didReceiveChallenge,%@",session);
    //挑战处理类型为 默认
    /*
    NSURLSessionAuthChallengePerformDefaultHandling：默认方式处理
    NSURLSessionAuthChallengeUseCredential：使用指定的证书
   NSURLSessionAuthChallengeCancelAuthenticationChallenge：取消挑战
    */
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                 if (credential) {
                    disposition = NSURLSessionAuthChallengeUseCredential;
                } else {
                    disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

- (NSString *)toJsonString:(NSDictionary *)dict{
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
    NSString *jsonString;
    if (!jsonData) {
        NSLog(@"[文件名：ccs] 转换 json 失败 %@",error);
    } else {
        jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    NSRange range = {0,jsonString.length};
    //去掉字符串中的空格
    [mutStr replaceOccurrencesOfString:@" " withString:@"" options:NSLiteralSearch range:range];
    NSRange range2 = {0,mutStr.length};
    //去掉字符串中的换行符
    [mutStr replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:range2];
    return mutStr;
}

#pragma mark CCSClientDelegate (这里的事件都委托给 IVCSSDK 处理，只把 IVCSSDK 暴露给用户)
-(void)onInvitationProgress:(NSDictionary *_Nonnull)progress{
    if(self.ivcsSDKDelegate && [self.ivcsSDKDelegate respondsToSelector:@selector(onInvitationProgress:)]){
        ZcoModelCcsMessage<ZcoModelInvitationProgress *> *ccsMessage = [[ZcoModelCcsMessage alloc] initWithDictionary:progress];
        ccsMessage.data = [[ZcoModelInvitationProgress alloc]initWithDictionary:[progress valueForKey:@"data"]];
        [self.ivcsSDKDelegate performSelector:@selector(onInvitationProgress:) withObject:ccsMessage];
    }
}
-(void)agentVideoReadyToTalk{
    if(self.ivcsSDKDelegate && [self.ivcsSDKDelegate respondsToSelector:@selector(agentVideoReadyToTalk)])
    [self.ivcsSDKDelegate performSelector:@selector(agentVideoReadyToTalk)];
    // [self.ivcsSDKDelegate agentVideoReadyToTalk];
}
-(void)onJoinSession:(NSDictionary *) dataInfo{
    if(self.ivcsSDKDelegate && [self.ivcsSDKDelegate respondsToSelector:@selector(onJoinSession:)]){
        ZcoModelMember *joinedInfo = [[ZcoModelMember alloc] initWithDictionary:dataInfo];
        [self.ivcsSDKDelegate performSelector:@selector(onJoinSession:) withObject:joinedInfo];
        // [self.ivcsSDKDelegate onJoinSession:joinedInfo];
    }
}
-(void)onQuitSession:(NSDictionary *)personInfo{
    if(self.ivcsSDKDelegate && [self.ivcsSDKDelegate respondsToSelector:@selector(onQuitSession:)]){
        ZcoModelMember *joinedInfo = [[ZcoModelMember alloc] initWithDictionary:personInfo];
        [self.ivcsSDKDelegate performSelector:@selector(onQuitSession:) withObject:joinedInfo];
        // [self.ivcsSDKDelegate onQuitSession:joinedInfo];
    }
}
-(void)onHoldOn{
    if(self.ivcsSDKDelegate && [self.ivcsSDKDelegate respondsToSelector:@selector(onHoldOn)])
        [self.ivcsSDKDelegate performSelector:@selector(onHoldOn)];
        // [self.ivcsSDKDelegate onHoldOn];
}

@end
